#pragma once

#include "Types.h"
#include "DLL.h"
#include "Language.h"

#include <exception>
#include <set>

namespace My {

class Doc;
class Frame;

#if defined(LoadString)
#undef LoadString
#endif

class DLL_API AppBase : public CWinApp {
public:
	AppBase();
public:
	/// Returns the document
	Doc & GetDoc();
	const Doc & GetDoc() const;
	/// Returns the main frame
	Frame & GetFrame();
	const Frame & GetFrame() const;
	/// Returns current activity
	String GetActivity() const;		
	/// Begins a new activity
	void BeginActivity(const String &);
	/// Ends current activity
	void EndActivity();
// Service methods
public:
	String LoadString(UINT nID);
	bool LoadFrame(Frame & f, UINT nID);
	bool OpenFile(const String &, int nFilter = -1);
	void SetLanguageModule(HMODULE);
	/// Call this to enable specific languages for this app
	void EnableLanguage(Language);
	/// The language which does not require additional modules
	void SetDefaultLanguage(Language);
	/// Call this from InitInstance
	void InitLanguage(const char * szSection, const char * szEntry);
	void UpdateLanguageMenu(CMenu *);
// Overridables
protected:
	/// Displays an error message
	virtual void ExceptionMessage(const char *);
	virtual Doc & GetDocRef() = 0;
	virtual Frame & GetFrameRef() = 0;
protected:
	virtual String GetOpenFileName(int & nFilter);
	virtual String GetSaveFileName(const String & def = String());
// Overrides
public:
	virtual int Run(); 	///< Guards message pump from unhandled exceptions, which are displayed to the user here
	virtual CDocument * OpenDocumentFile(LPCTSTR lpszFileName);
protected:
	virtual int RunNoStdException(); ///< Guards against std::exception only
protected:
	StringVector		m_Activities;
	AppLanguage			m_Language;
	std::set<Language>	m_Languages;
	Language			m_DefaultLanguage;
public:
	// Messages
	afx_msg void OnFileNew();
	afx_msg void OnUpdateFileNew(CCmdUI* pCmdUI);
	afx_msg void OnFileOpen();
	afx_msg void OnUpdateFileOpen(CCmdUI* pCmdUI);
	afx_msg void OnFileClose();
	afx_msg void OnUpdateFileClose(CCmdUI* pCmdUI);
	afx_msg void OnFileSave();
	afx_msg void OnUpdateFileSave(CCmdUI* pCmdUI);
	afx_msg void OnFileSaveAs();
	afx_msg void OnUpdateFileSaveAs(CCmdUI* pCmdUI);
	afx_msg void OnEditUndo();
	afx_msg void OnUpdateEditUndo(CCmdUI* pCmdUI);
	afx_msg void OnEditRedo();
	afx_msg void OnUpdateEditRedo(CCmdUI* pCmdUI);
	afx_msg void OnEditClear();
	afx_msg void OnUpdateEditClear(CCmdUI* pCmdUI);
	afx_msg void OnLanguage(UINT nID);
	afx_msg void OnUpdateLanguage(CCmdUI * pCmdUI);
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
	virtual BOOL PreTranslateMessage(MSG* pMsg);
};

DLL_API AppBase & GetApp();

template <typename D, typename F>
class App : public AppBase {
public:
	typedef D DocType;
	typedef F FrameType;
	typedef typename FrameType::ViewType ViewType;
public:
	App();
	~App();
public:
	DocType & GetDoc();
	const DocType & GetDoc() const;
	FrameType & GetFrame();
	const FrameType & GetFrame() const;
	ViewType & GetView();
	const ViewType & GetView() const;
// Overrides
public:
	virtual BOOL InitInstance();
	virtual int ExitInstance();
	virtual Doc & GetDocRef();
	virtual Frame & GetFrameRef();
protected:
	std::auto_ptr<DocType>		m_pDoc;
	std::auto_ptr<FrameType>	m_pFrame;
};

} // My

#include "Impl/App.inl"